import sounddevice as sd
import soundfile as sf
import numpy as np


class USBSpeaker:
    def __init__(self, device_name_keyword="USB"):
        self.device_info = self._find_usb_output_device(device_name_keyword)
        if not self.device_info:
            raise RuntimeError(
                f"USB speaker with keyword '{device_name_keyword}' not found."
            )
        self.device_index = self.device_info["index"]
        self.volume = 1.0
        self._playing = False  # 播放状态标志

    def _find_usb_output_device(self, keyword):
        for idx, dev in enumerate(sd.query_devices()):
            if (
                keyword.lower() in dev["name"].lower()
                and dev["max_output_channels"] > 0
            ):
                dev["index"] = idx
                return dev
        return None

    def set_volume(self, volume: float):
        if not (0.0 <= volume <= 1.0):
            raise ValueError("Volume must be between 0.0 and 1.0")
        self.volume = volume

    def play_wav(self, wav_path: str):
        data, samplerate = sf.read(wav_path, dtype="float32")
        data = self._apply_volume(data)
        self._playing = True
        sd.play(data, samplerate=samplerate, device=self.device_index)
        sd.wait()
        self._playing = False

    def play_array(self, array: np.ndarray, samplerate: int = 44100):
        data = self._apply_volume(array)
        self._playing = True
        sd.play(data, samplerate=samplerate, device=self.device_index)
        sd.wait()
        self._playing = False

    def stop(self):
        sd.stop()
        self._playing = False

    def is_playing(self):
        """判断当前是否正在播放"""
        return self._playing

    def get_device_info(self):
        return self.device_info

    def _apply_volume(self, data: np.ndarray):
        return np.clip(data * self.volume, -1.0, 1.0)
